#include "ModuleConvolute.h"

////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::init(QCVModuleHandlerInterface * parent)
{
  this->parent=parent;
  
  win=new QWidget();
  gridLayout=new QGridLayout();
  QHBoxLayout * hlayout=new QHBoxLayout();
  layout=new QVBoxLayout(win);
  
  sb_fact=new QDoubleSpinBox(),
  sb_fact->setRange(-100,100);
  sb_fact->setPrefix("f=");
  sb_fact->setSingleStep(0.01);
  bp_load=new QPushButton("Charger",win);
  bp_save=new QPushButton("Sauver",win);
  
  dimX=new QSpinBox(win);
  dimX->setPrefix("X=");
  dimX->setRange(1,51);
  dimX->setValue(3);
  dimX->setSingleStep(2.0);
  dimY=new QSpinBox(win);
  dimY->setPrefix("Y=");
  dimY->setRange(1,51);
  dimY->setValue(3);
  dimY->setSingleStep(2.0);
  
  hlayout->addWidget(dimX);
  hlayout->addWidget(dimY);
  hlayout->addWidget(sb_fact);
  hlayout->addWidget(bp_load);
  hlayout->addWidget(bp_save);
  layout->addLayout(hlayout);
  layout->addLayout(gridLayout);
  
  updateGridLayout(0);
  
  connect(sb_fact,SIGNAL(valueChanged(double)),this,SLOT(getMat(double)));
  connect(dimX,SIGNAL(valueChanged(int)),this,SLOT(updateGridLayout(int)));
  connect(dimY,SIGNAL(valueChanged(int)),this,SLOT(updateGridLayout(int)));  
  connect(bp_load,SIGNAL(clicked()),this,SLOT(s_load()));
  connect(bp_save,SIGNAL(clicked()),this,SLOT(s_save()));
    
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::free()
{
  delete win;
}
//////////////////////////////////////////////////////////////////////////////// 
cv::Mat & ModuleConvolute::process()
{
  cv::filter2D(frame,frame,-1, kernel,cv::Point(-1,-1));
  return frame;  
}
////////////////////////////////////////////////////////////////////////////////                                                  
void ModuleConvolute::setInput(int n,const cv::Mat & m)
{
  if(n==0)
  {
    frame=m.clone();
  }	
}
////////////////////////////////////////////////////////////////////////////////
QWidget* ModuleConvolute::widget()
{
  return win;
}
////////////////////////////////////////////////////////////////////////////////
QString ModuleConvolute::getName()
{
  return trUtf8("Convolution");
}
////////////////////////////////////////////////////////////////////////////////
int ModuleConvolute::nbInputs()
{
  return 1;
}
////////////////////////////////////////////////////////////////////////////////
bool ModuleConvolute::setParams(QString params)
{
	QStringList params_list=params.split(";");
	
	if(params_list.size()==1)
	{
		direct_load(params_list[0]);
		return true;
	}
	else
	{
		return false;
	}
}
QString ModuleConvolute::getParams()
{
	return matfile;
}

QCVModuleInterface * ModuleConvolute::clone()
{
	return new ModuleConvolute;
}
////////////////////////////////////////////////////////////////////////////////
QString ModuleConvolute::help(int id)
{
	if(id==-2)
	{
		 return tr("Module permettant de créer un noyeau de convolution.");
	}	
	else if(id==-1)
	{
		 return tr("image");
	}
	else if(id==0)
	{
		return tr("image");
	}
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::updateGridLayout(int n)
{                                                
  for(int i=0;i<kernel_data.size();i++)
  {
    delete kernel_data[i];
  }
  kernel_data.clear();
  
  for(int i=0;i<dimX->value();i++)
  {
    for(int j=0;j<dimY->value();j++)
    {
      QDoubleSpinBox * new_sb=new QDoubleSpinBox();
      new_sb->setRange(-100.0,100.0);
      new_sb->setValue(0.0);
      connect(new_sb,SIGNAL(valueChanged(double)),this,SLOT(getMat(double)));
      kernel_data+=new_sb;
      gridLayout->addWidget(new_sb,j,i);
    }
  }
  getMat(0);
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::getMat(int n)
{
  kernel.create(dimX->value(),dimY->value());
  kernel.setTo(0.0);
  for(int i=0;i<dimX->value();i++)
  {
    for(int j=0;j<dimY->value();j++)
    {
       kernel(i,j)=kernel_data[j*dimX->value()+i]->value()*sb_fact->value();
    }  
  }    
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::getMat(double n)
{
  kernel.create(dimX->value(),dimY->value());
  kernel.setTo(0.0);
  for(int i=0;i<dimX->value();i++)
  {
    for(int j=0;j<dimY->value();j++)
    {
       kernel(i,j)=kernel_data[j*dimX->value()+i]->value()*sb_fact->value();
    }  
  }    
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::s_load()
{
  QString filename=QFileDialog::getOpenFileName(NULL,"Ouvrir un noyau","kernels",tr("(*.cmat)"));
  QFile file(filename);
  if (file.open(QIODevice::ReadOnly | QIODevice::Text))
  {
		 matfile=filename;
     QTextStream in(&file);
     int dbuf=0;
     float fbuf=0;
      
     in>>dbuf;
     dimX->setValue(dbuf);
     in>>dbuf;
     dimY->setValue(dbuf);
     in>>fbuf;
     sb_fact->setValue(fbuf);
    
    for(int i=0;i<kernel_data.size();i++)
    {
        in>>fbuf;
        kernel_data[i]->setValue(fbuf);
    }
    
    getMat(0);
    
    file.close();
  }
  else
  {
  	QMessageBox::information(NULL,"Fichier de atrice introuvable",tr("Impossible de charger le fichier: ")+filename);
  }
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::direct_load(QString filename)
{
	QFile file(filename);
  if (file.open(QIODevice::ReadOnly | QIODevice::Text))
  {
		 matfile=filename;
     QTextStream in(&file);
     int dbuf=0;
     float fbuf=0;
      
     in>>dbuf;
     dimX->setValue(dbuf);
     in>>dbuf;
     dimY->setValue(dbuf);
     in>>fbuf;
     sb_fact->setValue(fbuf);
    
    for(int i=0;i<kernel_data.size();i++)
    {
        in>>fbuf;
        kernel_data[i]->setValue(fbuf);
    }
    
    getMat(0);
    
    file.close();
  }
  else
  {
  	QMessageBox::information(NULL,"Fichier de atrice introuvable",tr("Impossible de charger le fichier: ")+filename);
  }
}
////////////////////////////////////////////////////////////////////////////////
void ModuleConvolute::s_save()
{
  QString filename=QFileDialog::getSaveFileName(NULL,"Sauver un noyau","kernels",tr("(*.cmat)"));
  QFile file(filename);
  if (file.open(QIODevice::WriteOnly | QIODevice::Text))
  {
     QTextStream out(&file);
     
     out<<dimX->value()<<" "<<dimY->value()<<" "<<sb_fact->value()<<"\n";
     for(int i=0;i<kernel_data.size();i++)
     {
        out<<kernel_data[i]->value()<<" ";
        if((i+1)%dimX->value()==0)out<<"\n";
     }
     
     file.close();  
  }
}
////////////////////////////////////////////////////////////////////////////////
Q_EXPORT_PLUGIN2(ModuleConvolute_plugin,ModuleConvolute);                                                                               
